/********************************************
 *      堆串
 * Created by zlj on 2024/6/28.
********************************************/
#include "HString.h"
#include "string.h"

void InitHString(HString *s)
{
    s->ch = NULL;
    s->length = 0;
}

void PrintHString(HString *s)
{
    for (int i = 0; i < s->length; ++i)
    {
        printf("%c ", s->ch[i]);
    }
    printf("\n");
}

void HStrAssign(HString *s, char *str)
{
    int len = strlen(str);
    //这一步的目的是防止内存泄漏
    if (s->ch != NULL) //判断这个结构之前是否有为其分配空间
        free(s->ch);
    s->ch = (char *) malloc(sizeof(char) * len);//申请符合str大小的空间
    assert(s->ch != NULL);
    for (int i = 0; i < len; ++i)
    {
        s->ch[i] = str[i];
    }
    s->length = len;
}

/**
 * 将T拷贝到S
 * @param s
 * @param t
 */
void HStrCopy(HString *s, HString *t)
{
    int len = HStrLength(t);
    if (s->ch != NULL)
        free(s->ch);
    s->ch = (char *) malloc(sizeof(char) * len);
    assert(s->ch != NULL);
    for (int i = 0; i < len; ++i)
    {
        s->ch[i] = t->ch[i];
    }
    s->length = len;
}

bool HStrEmpty(HString *s)
{
    return s->length == 0;
}

int HStrCompare(HString *s, HString *t)
{
    if (s->length == 0 || t->length == 0)
        return 0;
    int result = 0;
    int i = 0, j = 0;
    //在两个字符串都还有字符可以进行比较时，不断的比较
    while (i < s->length && j < t->length)
    {
        //发现s比t大，返回1
        if (s->ch[i] > t->ch[j])
        {
            return 1;
        } else if (s->ch[i] < t->ch[j])
        {
            return -1;
        } else
        {
            i++;
            j++;
        }
    }
    //S还有剩余（S的前面部分与T完全相同）
    if (i < s->length)
        return 1;
    //T还有剩余（T的前面部分与S完全相同）
    if (j < t->length)
        return -1;
    return result;
}

int HStrLength(HString *s)
{
    return s->length;
}

/**
 * 将s1和s2拼接，存放入T
 * @param t
 * @param s1
 * @param s2
 */
void HStrConcat(HString *t, HString *s1, HString *s2)
{
    if (t->ch != NULL)
        free(t->ch);
    int len1 = HStrLength(s1);
    int len2 = HStrLength(s2);
    t->ch = (char *) malloc(sizeof(char) * (len1 + len2));
    assert(t->ch != NULL);
    //分配成功
    int i = 0;
    for (; i < len1; ++i)
    {
        t->ch[i] = s1->ch[i];
    }
    for (int j = 0; j < len2; ++j)
    {
        t->ch[i + j] = s2->ch[j];
    }
    t->length = (len1 + len2);
}

/**
 * 子串截取：从S的pos取len长度的字符串放入sub中
 * @param s 原串
 * @param sub 子串
 * @param pos 从哪个位置
 * @param len 要截取的长度
 */
void HStrSubString(HString *s, HString *sub, int pos, int len)
{
    //条件
    if (pos < 0 || pos > s->length || len < 0 || len > s->length - pos)
        return;
    if (sub->ch != NULL)
    {
        free(sub->ch);
    }
    //获取要截取子串的大小
    sub->ch = (char *) malloc(sizeof(char) * len);
    assert(sub->ch != NULL);
    int j = pos; //设置要截取的位置
    for (int i = 0; i < len; ++i)
    {
        sub->ch[i] = s->ch[j + i];
    }
    sub->length = len;
}

/**
 * 插入字符串:将T插入到S的pos位置
 * @param s
 * @param pos
 * @param t
 */
void HStrInsert(HString *s, int pos, HString *t)
{
    if (t->length == 0)
        return;
    if (pos < 0 || pos > s->length)
        return;
    //为S扩充存储空间，存储空间扩充为足够容纳S+T内的字符
    char *ch = (char *) realloc(s->ch, sizeof(char) * (s->length + t->length));
    assert(ch != NULL);
    s->ch = ch;
    //移动注意是由后往前，这样才不会将数据覆盖
    for (int i = s->length - 1; i > pos; --i)
    {
        s->ch[i + t->length] = s->ch[i];
    }
    int j = pos;
    for (int i = 0; i < t->length; ++i)
    {
        s->ch[j + i] = t->ch[i];
    }
    s->length += t->length;
}

/**
 * 删除字符串：删除字符串S中从pos位置开始的len长度子串
 * @param s
 * @param pos
 * @param len
 */
void HStrDelete(HString *s, int pos, int len)
{
    if (pos < 0 || pos > s->length)
        return;
    if (len <= 0 || len > s->length)
        return;
    int j = pos;
    for (int i = j + len; i < s->length; ++i)
    {
        s->ch[i - len] = s->ch[i];
    }
    s->length -= len;
}

/**
 * 清空
 * @param s
 */
void HStrClear(HString *s)
{
    s->length == 0;
    if (s->ch != NULL)
        free(s->ch);
    s->ch = NULL;
}

/**
 * 匹配
 * @param s
 * @param t
 * @param pos
 * @return
 */
int HStrIndex(HString *s, HString *t, int pos)
{
    int i = pos; //主串开始匹配的初始位置
    int j = 0;
    while (i != s->length && j != t->length)
    {
        //如果有字符匹配则，将主串和模式串分别下移一个字符
        if (s->ch[i] == t->ch[j])
        {
            i++;
            j++;
        }
            //如果在匹配的过程中，中断了，出现了不匹配
        else
        {
            i = i - j + 1;
            j = 0;
        }
    }
    if (j == t->length)
        return i - j;
    return -1;
}

/**
 * 替换字符串：将字符串S中出现的T全部替换成V
 * @param s
 * @param t
 * @param v
 */
void HStrReplace(HString *s, HString *t, HString *v)
{
    int s_len = HStrLength(s);
    int t_len = HStrLength(t);
    int v_len = HStrLength(v);
    int index = -1;
    int pos = 0;

    while (pos < s_len)
    {
        index = HStrIndex(s, t, pos);
        if (index == -1)
        {
            return;
        }
        HStrDelete(s, index, t_len);
        HStrInsert(s, index, v);
        pos = index + v_len; //这个位置是替换前模式串所在的首位置加上替换的字符串长度
    }
}